#include <cv.h>
#include <highgui.h>
#include <iostream>
#include <opencv2/gpu/gpu.hpp>
#include <opencv2/contrib/contrib.hpp>
#include <ctime>
#include "mi.hpp"
#include "imagemain.hpp"
# include "asa047.hpp"
using namespace cv;
using namespace std;

Mat imageRGB1Channel,
    imageGray1Channel;

void imageMain()
{

	 Mat imageRGB3Channels,
	     imageGray3Channels,
	     imageGray1ChannelRotated;


	 float	 alpha       = 0,
		     beta        = 0,
		     minAngle[1] = {0};


	 clock_t t;
	t = clock();
	printf ("Calculating...\n");

	 alpha = image_Read(imageRGB3Channels,imageGray1Channel);



	 image_Convert3To1Channels(imageRGB3Channels,imageRGB1Channel);
	 /////////////////////////////////////////////////////

	 /// Manipulation MI
	  minAngle[0] = connect_Mutual_Information_to_Simplex();

imageGray1ChannelRotated =  rotate( imageGray1Channel,  minAngle);


imshow( "IimageGray1ChannelRotated", imageGray1ChannelRotated);

	 	  afterSimpex (imageGray1ChannelRotated,
	 	 		       imageGray3Channels,
	 	 		       imageRGB3Channels,
	 	 		       alpha,
	 	 		       beta);


t = clock() - t;
printf ("It took me %d clicks (%f seconds).\n",t,((float)t)/CLOCKS_PER_SEC);


}

float wrapper_Mutual_Information(float angle[])
{
  float result = 0.0;


	Mat imageGray1ChannelReturned;

	imageGray1ChannelReturned =  rotate( imageGray1Channel, angle);

	result =   calculate_Mutual_Information(imageRGB1Channel,imageGray1ChannelReturned);

	result  =  -1 * result;

	cout<< result<<endl;

	return result;
}


float connect_Mutual_Information_to_Simplex()
{

	  int icount,
	      ifault,
	      kcount,
	      konvge,
	      numres,
	           n,
               i;
	float ynewlo,
	  	  reqmin,
	      *start,
	       *step,
	       *xmin;

	  n = 1;

	  start = new float[n];
	  step  = new float[n];
	  xmin  = new float[n];

	  cout << "\n";
	  cout << "************************MI TEST************************\n";
	  cout << "  Apply NELMIN to Mutual Information function.\n";

	  start[0] =  11.0;


	  //reqmin = 1.0E-02;

	  reqmin  = 0.01;

	  step[0] = 0.5;
	 // step[1] = 1.0;

	  konvge = 10;
	  kcount = 50;

	  cout << "\n";
	  cout << "  Starting point X:\n";
	  cout << "\n";

	  for ( i = 0; i < n; i++ )
	  {
	    cout << "  " << setw(14) << start[i] << "\n";
	  }

	  ynewlo = wrapper_Mutual_Information ( start );

	  cout << "\n";
	  cout << "  F(X) = " << ynewlo << "\n";

	  nelmin ( wrapper_Mutual_Information, n, start, xmin, &ynewlo, reqmin, step,
	    konvge, kcount, &icount, &numres, &ifault );

	  cout << "\n";
	  cout << "  Return code IFAULT = " << ifault << "\n\n";

	  cout << "  Estimate of minimizing value X*:\n\n";

	  for ( i = 0; i < n; i++ )
	  {
	    cout << "  " << setw(14) << xmin[i] << "\n";
	  }

	  cout << "\n";
	  cout << "  F(X*) = " << ynewlo << "\n\n";


	  cout << "  Number of iterations = " << icount << "\n";
	  cout << "  Number of restarts =   " << numres << "\n";


	  delete [] start;
	  delete [] step;

	 return xmin[0];

}


void afterSimpex (Mat & imageGray1ChannelRotated,
		          Mat & imageGray3Channels,
		          Mat & imageRGB3Channels,
		          float alpha, float beta)
{

	Mat  imageGray3ChannelsResizedFalseColor,
	  	      	   imageGray3ChannelsResized,
	  	      	    imageRGB3ChannelsResized,
	  	      	    	   ImageFusionResult;

	int                           factor = 3;

	image_Convert1To3Channels(imageGray1ChannelRotated,imageGray3Channels);
	imageRGB3ChannelsResized  = image_Resize(factor,imageRGB3Channels);
	imageGray3ChannelsResized = image_Resize(factor,imageGray3Channels);




	applyColorMap(imageGray3ChannelsResized, imageGray3ChannelsResizedFalseColor, COLORMAP_JET);

	beta = ( 1.0 - alpha );

	cout<<"Alpha: "<<alpha<<endl;

	// Add both 3 channel images RGB and GRAY
	addWeighted( imageRGB3ChannelsResized, 0.5, imageGray3ChannelsResizedFalseColor, 0.5, 0.0, ImageFusionResult);

	//imshow( "imageRGB3ChannelsResized", imageRGB3ChannelsResized );
	//imshow( "imageGray3ChannelsResized", imageGray3ChannelsResized);
	//imshow( "imageGray3ChannelsResizedFalseColor", imageGray3ChannelsResizedFalseColor);
	imshow( "Image Fusion Result", ImageFusionResult);

	waitKey(0);

}
Mat rotate(Mat src, float angle[])
{
    Mat dst;
    Point2f pt(src.cols/2, src.rows/2);
    Mat r = getRotationMatrix2D(pt, angle[0], 1.0);
    warpAffine(src, dst, r, Size(src.cols, src.rows),WARP_INVERSE_MAP);

  return dst;
}

float image_Read(Mat & imageRGB3Channels, Mat & imageGray1Channel)
{

    float alpha = 0.5; float input;

    imageRGB3Channels = imread("/home/erman/cuda-workspace/MutualInformation/src/img_00000.bmp", CV_LOAD_IMAGE_COLOR);
    imageGray1Channel = imread("/home/erman/cuda-workspace/MutualInformation/src/img_00001.bmp", CV_LOAD_IMAGE_GRAYSCALE);


    /// Ask the user enter alpha
    std::cout<<" Simple Linear Blender "<<std::endl;
    std::cout<<"-----------------------"<<std::endl;
    std::cout<<"* Enter alpha [0-1]: ";
   // std::cin>>input;

    /// We use the alpha provided by the user if it is between 0 and 1
    //if( input >= 0.0 && input <= 1.0 ) { alpha = input; }
    if( !imageRGB3Channels.data )      { printf("Error loading src1 \n"); return -1; }
    if( !imageGray1Channel.data )      { printf("Error loading src2 \n"); return -1; }


  return alpha;

}

void image_Convert3To1Channels(Mat & image3Channels, Mat & image1Channel)
{

	 // convert an image from 3 channels to 1 channel
	 cvtColor(image3Channels, image1Channel, CV_RGB2GRAY);

}

void image_Convert1To3Channels(Mat & image1Channel, Mat & image3Channels)
{
	 // Convert 1 channel gray image to 3 channel gray image
	 cvtColor(image1Channel, image3Channels, CV_GRAY2RGB);

}


Mat image_Resize(int factor, Mat & image3Channels )
{

	 // Define resized Mat objects for 3 channel images
	 Mat  image3ChannelsResized(factor * image3Channels.size().height, factor * image3Channels.size().width, image3Channels.type());

	 // Initialize resized Mat objects for 1 channel images
	 resize(image3Channels, image3ChannelsResized,  image3ChannelsResized.size(), 0, 0, INTER_CUBIC  );

  return image3ChannelsResized;
}



